package com.dhj.yygh.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dhj.yygh.client.DictFeignClient;
import com.dhj.yygh.common.exception.YyghException;
import com.dhj.yygh.common.result.ResultCodeEnum;
import com.dhj.yygh.common.utils.MD5;
import com.dhj.yygh.mapper.HospitalSetMapper;
import com.dhj.yygh.model.hosp.Department;
import com.dhj.yygh.model.hosp.Hospital;
import com.dhj.yygh.model.hosp.HospitalSet;
import com.dhj.yygh.mongo_operation.HospitalRepository;
import com.dhj.yygh.mongo_operation.MyMongoTemplate;
import com.dhj.yygh.service.HospitalService;
import com.dhj.yygh.service.HospitalSetService;
import com.dhj.yygh.vo.hosp.HospitalQueryVo;
import com.dhj.yygh.vo.order.SignInfoVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class HospitalServiceImpl implements HospitalService {

    @Autowired
    private HospitalRepository hospitalRepository;

    @Autowired
    private MyMongoTemplate mongoTemplate;

    @Autowired
    private HospitalSetService hospitalSetService;

    @Autowired
    private HospitalSetMapper hospitalSetMapper;


    // 远程调用的 feign 接口
    @Autowired
    private DictFeignClient dictFeignClient;

    // 上传医院
    @Override
    public void save(Map<String, Object> parameterMap) {
        /*
         如果是第一次添加，直接添加到数据库
         若原本没有在 mongodb 中创建数据库，则通过配置文件中 mongodb 连接的 url 中指定的数据库名称进行创建
         这里创建了一个 yygh_hosp 数据库
         */

        // json 将参数的 parameterMap 转化为 json 字符串
        String str = JSONObject.toJSONString(parameterMap);

        // 将 json 字符串转化为 Java对象
        Hospital hospital = JSONObject.parseObject(str, Hospital.class);

        // 通过 hoscode 判断该数据是否存在,
        String hoscode = hospital.getHoscode();

        //Hospital hospitalExist = hospitalRepository.getHospitalByHoscode(hoscode);
        // 使用 mongoTemplate 的方式来操作 mongo 方便理解
        Hospital hospitalExist = mongoTemplate.findHospitalByHoscode(hoscode);


        // 如果存在，做修改操作
        if (hospitalExist != null) {
            // 其状态使用已经存在的信息
            hospital.setStatus(hospitalExist.getStatus());
            // 创建时间信息不变
            hospital.setCreateTime(hospitalExist.getCreateTime());

            // 更新修改的时间，其他信息不变，使用传递进来的新信息
            hospital.setUpdateTime(new Date());
            hospital.setIsDeleted(0);

            /*
             需要设置 id 使得 HospitalRepository 会判断是否有 id 值 若有 id 值才会执行修改操作
             否则重复添加会报错
             */
            hospital.setId(hospitalExist.getId());

            // 保存到数据库
            hospitalRepository.save(hospital);
        } else {
            // 否则做添加操作
            hospital.setCreateTime(new Date());
            hospital.setUpdateTime(new Date());
            hospital.setIsDeleted(0);
            hospital.setStatus(1);
            hospitalRepository.save(hospital);
        }
    }

    // 根据医院 hoscode 查询医院信息
    @Override
    public Hospital getHospitalByHoscode(String hoscode) {
        return mongoTemplate.findHospitalByHoscode(hoscode);
    }

    // 签名校验
    @Override
    public boolean checkSignKey(Map<String, Object> stringObjectMap) {

        String sign = (String) stringObjectMap.get("sign"); // 医院传传递过来的 MD5 加密 signKey

        String hoscode = (String) stringObjectMap.get("hoscode");

        String hospitalSetSignKey = hospitalSetService.getHospitalSetSignKey(hoscode);

        // 服务端根据医院 hoscode 从数据库查询出的 MD5 加密 signKey
        String encrypt = MD5.encrypt(hospitalSetSignKey);

        return encrypt.equals(sign);
    }

    /**
     * 分页查询医院信息
     *
     * @param page            当前页
     * @param pageCount       每页记录数
     * @param hospitalQueryVo 条件查询 vo 对象
     * @return
     */
    @Override
    public Page<Hospital> selectHospitalPage(Integer page, Integer pageCount, HospitalQueryVo hospitalQueryVo) {

        Hospital hospital = new Hospital();
        BeanUtils.copyProperties(hospitalQueryVo, hospital);

        // 构造模糊查询条件
        ExampleMatcher matcher = ExampleMatcher.matching()
                // 通过字符串来匹配,匹配模式为 StringMatcher.CONTAINING: 包含
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
                .withIgnoreCase(true); // 忽略大小写

        // 构造条件
        Example<Hospital> example = Example.of(hospital, matcher);

        // 构造 Pageable 对象
        Pageable pageable = PageRequest.of(page, pageCount);

        Page<Hospital> hospitalsPage = hospitalRepository.findAll(example, pageable);

        // 得到医院数据的集合
        List<Hospital> content = hospitalsPage.getContent();

        // 遍历医院集合，封装医院等级 | 地区信息
        for (Hospital hosp : content) {
            hosp = this.setHospitalInfo(hosp);
        }
        return hospitalsPage;
    }

    // 通过远程调用，根据 dictCode 和 value 获取到医院等级,封装到 Hospital 中
    private Hospital setHospitalInfo(Hospital hosp) {

        // 医院的等级信息
        String name = dictFeignClient.getDictByDictcodeAndValue("Hostype", hosp.getHostype());

        // 远程调用获取到医院的省份信息
        String provinceName = dictFeignClient.getDictByValue(hosp.getProvinceCode());

        // 远程调用获取医院的市信息
        String cityName = dictFeignClient.getDictByValue(hosp.getCityCode());

        // 远程调用获取医院的区信息
        String districtName = dictFeignClient.getDictByValue(hosp.getDistrictCode());

        // 参数封装
        hosp.getParam().put("name", name);
        hosp.getParam().put("provinceName", provinceName);
        hosp.getParam().put("fullAddress",
                provinceName + "|" // 省
                        + cityName + "|" // 市
                        + districtName + "|" // 区
                        + hosp.getAddress()); // 详细地址
        return hosp;
    }


    /**
     * 修改医院状态信息
     *
     * @param id     id
     * @param status 状态值
     */
    @Override
    public Hospital updateHospitalStatus(String id, Integer status) {
        Hospital hospita = hospitalRepository.findById(id).get();

        hospita.setStatus(status);

        Hospital save = hospitalRepository.save(hospita);

        return save;
    }

    /**
     * 根据医院 id 获取医院的详情信息
     *
     * @param id 医院 id
     * @return 返回医院实体对象
     */
    @Override
    public Map<String, Object> getHospitalDetailsById(String id) {
        // 这里直接返回 hospital 对象也是可以的，但是为了前端取值方便，使用 Map 来返回值
        Map<String, Object> map = new HashMap<>();
        Hospital hospital = hospitalRepository.findById(id).get();

        // 设置其中的省份 | 等级 | 详细地址等信息
        hospital = setHospitalInfo(hospital);

        map.put("hospital", hospital);
        map.put("bookingRule", hospital.getBookingRule());

        // 清空原本的 bookingRule 防止重复返回
        hospital.setBookingRule(null);

        return map;
    }

    /**
     * 根据医院名称进行模糊查询
     *
     * @param hosname 医院名称
     * @return
     */
    @Override
    public List<Hospital> getHospitalByHosname(String hosname) {
        return hospitalRepository.findHospitalByHosnameLike(hosname);
    }

    /**
     * 根据 hoscode 获取医院详情
     *
     * @param hoscode 医院代码
     * @return
     */
    @Override
    public Map<String, Object> getHospitalDetailsByHoscode(String hoscode) {
        // 这里直接返回 hospital 对象也是可以的，但是为了前端取值方便，使用 Map 来返回值
        Map<String, Object> map = new HashMap<>();
        Hospital hospital = getHospitalByHoscode(hoscode);

        // 设置其中的省份 | 等级 | 详细地址等信息
        hospital = setHospitalInfo(hospital);

        map.put("hospital", hospital);
        map.put("bookingRule", hospital.getBookingRule());

        // 清空原本的 bookingRule 防止重复返回
        hospital.setBookingRule(null);

        return map;
    }

    /**
     * 根据医院代码获取医院签名相关信息
     *
     * @param hoscode 医院代码
     * @return 返回签名相关信息的 vo 对象
     */
    @Override
    public SignInfoVo getSignInfoVo(String hoscode) {
        QueryWrapper<HospitalSet> wrapper = new QueryWrapper<>();
        wrapper.eq("hoscode", hoscode);
        HospitalSet hospitalSet = hospitalSetMapper.selectOne(wrapper);
        if (null == hospitalSet) {
            throw new YyghException(ResultCodeEnum.HOSPITAL_OPEN);
        }
        SignInfoVo signInfoVo = new SignInfoVo();
        signInfoVo.setApiUrl(hospitalSet.getApiUrl());
        signInfoVo.setSignKey(hospitalSet.getSignKey());
        return signInfoVo;
    }
}
